]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
shell-app: remove child_setup from app launching
authorDaniel Drake <drake@endlessm.com>
Wed, 6 Jun 2018 13:07:17 +0000 (07:07 -0600)
committerFlorian Müllner <florian.muellner@gmail.com>
Mon, 30 Jul 2018 23:11:41 +0000 (23:11 +0000)
When the amount of free memory on the system is somewhat low, gnome-shell
will sometimes fail to launch apps, reporting the error:
  fork(): Cannot allocate memory

fork() is failing here because while cloning the process virtual address
space, Linux worries that the thread being forked may end up COWing the
entire address space of the parent process (gnome-shell, which is
memory-hungry), and there is not enough free memory to permit that to
happen. This check is somewhat irrelevant because we are only forking
to immediately exec(), which will discard the whole virtual address
space anyway.

This issue can be avoided by using a new optimized gspawn codepath in
the latest glib development version, which uses posix_spawn() internally.

For the optimized codepath to be used, we must not pass a child_setup
function, so the the file descriptor management is reimplemented here
using new glib API to pass fds to the child process. The old API will
continue to be used on older glib versions.

We must also change the spawn flags for this code path to be hit.
I checked that gnome-shell's open file descriptors are all CLOEXEC
so using G_SPAWN_LEAVE_DESCRIPTORS_OPEN should be safe.

This will result in more resilient app launching when memory is low,
since the optimized spawn path avoids cloning the virtual address
space of the parent process (gnome-shell) and avoids the irrelevant
memory overcommit check.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/132

config.h.meson
meson.build
src/shell-app.c

index 10cadf98bf22c7666e43ef0ad532028a80cabaab..0dac17b9478a7768c3886e819a75348342d27676 100644 (file)
@@ -24,3 +24,6 @@
 
 /* Define if _NL_TIME_FIRST_WEEKDATE is available */
 #mesondefine HAVE__NL_TIME_FIRST_WEEKDAY
+
+/* Define if you have the `g_desktop_app_info_launch_uris_as_manager_with_fds` function */
+#mesondefine HAVE_GIO_DESKTOP_LAUNCH_URIS_WITH_FDS
index 65f6c7f1fb655250f5331bee3813a3b1c8e6e551..5750b4fecd3239e03b0b7a91bf91ca53156cf9c6 100644 (file)
@@ -161,6 +161,11 @@ cdata.set_quoted('PACKAGE_VERSION', meson.project_version())
 cdata.set('HAVE_NETWORKMANAGER', have_networkmanager)
 cdata.set('HAVE_SYSTEMD', have_systemd)
 
+# New API added in glib-2.57.2
+cdata.set('HAVE_GIO_DESKTOP_LAUNCH_URIS_WITH_FDS',
+          cc.has_function('g_desktop_app_info_launch_uris_as_manager_with_fds',
+                          dependencies : gio_dep)
+)
 cdata.set('HAVE_FDWALK', cc.has_function('fdwalk'))
 cdata.set('HAVE_MALLINFO', cc.has_function('mallinfo'))
 cdata.set('HAVE_SYS_RESOURCE_H', cc.has_header('sys/resource.h'))
index 6b726514a2fcedbc3366cc9f793f03da5432d42b..bb3f0b1712a420fd239fdad477be8a939b809e8f 100644 (file)
@@ -1207,7 +1207,7 @@ shell_app_request_quit (ShellApp   *app)
   return TRUE;
 }
 
-#ifdef HAVE_SYSTEMD
+#if !defined(HAVE_GIO_DESKTOP_LAUNCH_URIS_WITH_FDS) && defined(HAVE_SYSTEMD)
 /* This sets up the launched application to log to the journal
  * using its own identifier, instead of just "gnome-session".
  */
@@ -1255,6 +1255,7 @@ shell_app_launch (ShellApp     *app,
   ShellGlobal *global;
   GAppLaunchContext *context;
   gboolean ret;
+  GSpawnFlags flags;
 
   if (app->info == NULL)
     {
@@ -1274,9 +1275,39 @@ shell_app_launch (ShellApp     *app,
   if (discrete_gpu)
     g_app_launch_context_setenv (context, "DRI_PRIME", "1");
 
+  /* Set LEAVE_DESCRIPTORS_OPEN in order to use an optimized gspawn
+   * codepath. The shell's open file descriptors should be marked CLOEXEC
+   * so that they are automatically closed even with this flag set.
+   */
+  flags = G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD |
+          G_SPAWN_LEAVE_DESCRIPTORS_OPEN;
+
+#ifdef HAVE_GIO_DESKTOP_LAUNCH_URIS_WITH_FDS
+  /* Optimized spawn path, avoiding a child_setup function */
+  {
+    int journalfd = -1;
+
+#ifdef HAVE_SYSTEMD
+    journalfd = sd_journal_stream_fd (shell_app_get_id (app), LOG_INFO, FALSE);
+#endif /* HAVE_SYSTEMD */
+
+    ret = g_desktop_app_info_launch_uris_as_manager_with_fds (app->info, NULL,
+                                                              context,
+                                                              flags,
+                                                              NULL, NULL,
+                                                              wait_pid, NULL,
+                                                              -1,
+                                                              journalfd,
+                                                              journalfd,
+                                                              error);
+
+    if (journalfd >= 0)
+      (void) close (journalfd);
+  }
+#else /* !HAVE_GIO_DESKTOP_LAUNCH_URIS_WITH_FDS */
   ret = g_desktop_app_info_launch_uris_as_manager (app->info, NULL,
                                                    context,
-                                                   G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
+                                                   flags,
 #ifdef HAVE_SYSTEMD
                                                    app_child_setup, (gpointer)shell_app_get_id (app),
 #else
@@ -1284,6 +1315,7 @@ shell_app_launch (ShellApp     *app,
 #endif
                                                    wait_pid, NULL,
                                                    error);
+#endif /* HAVE_GIO_DESKTOP_LAUNCH_URIS_WITH_FDS */
   g_object_unref (context);
 
   return ret;